﻿// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace TheOliver.Controls
{
    public class ShiverBehavior : TriggerAction<UIElement>
    {
        TranslateTransform shiverTransform = new TranslateTransform();
        Storyboard shiverStory = new Storyboard();
        ElasticEase ease = new ElasticEase();
        DoubleAnimation shiverAnimation = new DoubleAnimation();

        public ShiverBehavior()
            : base()
        {
            // Set up ease
            ease.Springiness = 2;

            // Create the Animation
            shiverAnimation.EasingFunction = ease;
            Storyboard.SetTarget(shiverAnimation, shiverTransform);

            // Setup Variable Properties
            SetupProperties();

            // Attach it to the story
            shiverStory.Children.Add(shiverAnimation);
        }

        void SetupProperties()
        {
            ease.Oscillations = Oscillations;
            shiverAnimation.From = (double)0 - ShiverSize / 2;
            shiverAnimation.To = (double)ShiverSize / 2;
            shiverAnimation.Duration = ShiverDuration;
            Storyboard.SetTargetProperty(shiverAnimation, new PropertyPath(ShiverDirection == Orientation.Horizontal ? "X" : "Y"));
        }

        #region Oscillations (DependencyProperty)

        /// <summary>
        /// Number of Oscillations in the Behavior
        /// </summary>
        public int Oscillations
        {
            get { return (int)GetValue(OscillationsProperty); }
            set { SetValue(OscillationsProperty, value); }
        }
        public static readonly DependencyProperty OscillationsProperty =
            DependencyProperty.Register("Oscillations", typeof(int), typeof(ShiverBehavior),
            new PropertyMetadata(25, new PropertyChangedCallback(OnOscillationsChanged)));

        private static void OnOscillationsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ShiverBehavior)d).OnOscillationsChanged(e);
        }

        protected virtual void OnOscillationsChanged(DependencyPropertyChangedEventArgs e)
        {
            SetupProperties();
        }
        #endregion


        #region ShiverSize (DependencyProperty)

        /// <summary>
        /// The depth of the shiver
        /// </summary>
        public int ShiverSize
        {
            get { return (int)GetValue(ShiverSizeProperty); }
            set { SetValue(ShiverSizeProperty, value); }
        }
        public static readonly DependencyProperty ShiverSizeProperty =
            DependencyProperty.Register("ShiverSize", typeof(int), typeof(ShiverBehavior),
            new PropertyMetadata(10, new PropertyChangedCallback(OnShiverSizeChanged)));

        private static void OnShiverSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ShiverBehavior)d).OnShiverSizeChanged(e);
        }

        protected virtual void OnShiverSizeChanged(DependencyPropertyChangedEventArgs e)
        {
            SetupProperties();
        }
        #endregion


        #region ShiverDirection (DependencyProperty)

        /// <summary>
        /// Direction of the Shiver
        /// </summary>
        public Orientation ShiverDirection
        {
            get { return (Orientation)GetValue(ShiverDirectionProperty); }
            set { SetValue(ShiverDirectionProperty, value); }
        }
        public static readonly DependencyProperty ShiverDirectionProperty =
            DependencyProperty.Register("ShiverDirection", typeof(Orientation), typeof(ShiverBehavior),
            new PropertyMetadata(Orientation.Horizontal, new PropertyChangedCallback(OnShiverDirectionChanged)));

        private static void OnShiverDirectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ShiverBehavior)d).OnShiverDirectionChanged(e);
        }

        protected virtual void OnShiverDirectionChanged(DependencyPropertyChangedEventArgs e)
        {
            SetupProperties();
        }
        #endregion


        #region ShiverDuration (DependencyProperty)

        /// <summary>
        /// The duration of the Shiver
        /// </summary>  
        public TimeSpan ShiverDuration
        {
            get { return (TimeSpan)GetValue(ShiverDurationProperty); }
            set { SetValue(ShiverDurationProperty, value); }
        }
        public static readonly DependencyProperty ShiverDurationProperty =
            DependencyProperty.Register("ShiverDuration", typeof(TimeSpan), typeof(ShiverBehavior),
            new PropertyMetadata(TimeSpan.FromSeconds(2), new PropertyChangedCallback(OnShiverDurationChanged)));

        private static void OnShiverDurationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ShiverBehavior)d).OnShiverDurationChanged(e);
        }

        protected virtual void OnShiverDurationChanged(DependencyPropertyChangedEventArgs e)
        {
            SetupProperties();
        }

        #endregion

        protected override void OnAttached()
        {
            base.OnAttached();

            // Attach the transform
            if (this.AssociatedObject.RenderTransform == null)
            {
                this.AssociatedObject.RenderTransform = shiverTransform;
            }
            else if (this.AssociatedObject.RenderTransform is TransformGroup)
            {
                TransformGroup group = (TransformGroup)AssociatedObject.RenderTransform;
                group.Children.Add(shiverTransform);
            }
            else
            {
                var tx = AssociatedObject.RenderTransform;
                var group = new TransformGroup();
                group.Children.Add(tx);
                group.Children.Add(shiverTransform);
                AssociatedObject.RenderTransform = group;
            }
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();

            // Attach the transform
            if (this.AssociatedObject.RenderTransform is TransformGroup)
            {
                ((TransformGroup)AssociatedObject.RenderTransform).Children.Remove(shiverTransform);
            }
            else
            {
                AssociatedObject.RenderTransform = null;
            }
        }

        protected override void Invoke(object parameter)
        {
            shiverStory.Begin();
        }

    }
}
